$def with (pid, prog, p_name)

$var title: $_(u'SIP Modify Program')
$var page: programs

$code:
    def two_digits(n):
        return '%02d' % int(n)

    snames = gv.snames
    idd = int(gv.sd['idd'])
    if pid < 0: #  A new program
        program = {}
        program['enabled'] = 1 
        program['day_mask'] =  127 
        program['interval_base_day'] = 0
        program['start_min'] = 360
        program['stop_min'] = 1080
        program['cycle_min'] = 0
        program['duration_sec'] = [[0], [0] * gv.sd['nst']][idd]
        program['station_mask'] = [0] * gv.sd['nbrd']
        program['type'] = 'alldays'
        program['name'] = ""

    else: #  An existing program
        program = eval(prog)            ### format conversion
        # program = json.load(prog)            ### format conversion
    weekly = int(program['type'] in ['alldays', 'evendays', 'odddays'])
    stationsShown = 0
    for bid in range(gv.sd['nbrd']):        
        boardShow = gv.sd['show'][bid]
        for s in range(8):
            stationsShown += (boardShow>>s) & 1

    duration = 0
    sid = -1
    for b in range(gv.sd['nbrd']):
        for s in range(8):
            sid += 1
            if program['station_mask'][b] & (1 << s):
                if gv.sd['seq']:
                    if idd:
                        duration += program['duration_sec'][sid]
                    else:
                        duration += program['duration_sec'][0]
                else:
                    if idd :
                        duration = max(duration, program['duration_sec'][sid])
                    else:
                        duration = program['duration_sec'][0]

    # lap_end = program['start_min'] + duration // 60
    # recurring = int(lap_end) < int(program['stop_min'])
    
    recurring = int(program['cycle_min'] != 0)
    even = (program['type'] == 'evendays')
    odd = (program['type'] == 'odddays')
    tf = gv.sd['tf']
    def formatTime(t):
        if gv.sd['tf']:
            return t
        else:
            hour = int(t[0:2])
            newhour = hour
            if hour == 0:
                newhour = 12
            if hour > 12:
                newhour = hour-12
            return str(newhour)  + t[2:] + (" am" if hour<12 else " pm")
            
    def pdays(days, dayInterval):
        days = days & 0x7f
        daysRemaining = ((days + dayInterval)-(gv.dse % dayInterval)) % dayInterval
        return daysRemaining

<script>
        
    let prog = JSON.parse($:{"'" + json.dumps(program) + "'"});   ///// format conversion

    // Helper functions
    function parseTime(prefix) { 
        let h = parseInt(jQuery("#" + prefix + "h").val());
        let m = parseInt(jQuery("#" + prefix + "m").val());
        if (prefix.indexOf("i") < 0 && !timeFormat) {
            let f = jQuery("#" + prefix + "f").val();
            if (f == "PM") {
                if (h != 12) {
                    h += 12;
                }
            } else {
                if (h == 12) {
                    h = 0;
                }
            }
        }
        if (!(h >= 0 && h < 24 && m >= 0 && m < 60)) {
            alert($:{json.dumps(_(u'Incorrect time input '), ensure_ascii=False)} + prefix + ".");
            return -1;
        }
        return h * 60 + m;
    }

    function checkConsistency() {
        disableSubmit = false;
        errorHint = "";
        if (jQuery("button#cWeeklyInterval").hasClass("on") &&
            jQuery(".weekday.on").length < 1) {
            disableSubmit = true;
            errorHint = $:{json.dumps(_(u'Please choose at least one weekday for the program to run.'), ensure_ascii=False)};
        }
        if (jQuery(".station.on").length < 1) {
            disableSubmit = true;
            errorHint = $:{json.dumps(_(u'Please choose at least one station to run in this program.'), ensure_ascii=False)};
        }
        jQuery("button#cSubmit").prop("disabled", disableSubmit);
        jQuery("#errorHint").text(errorHint);
    }

    // Initialize behaviors
    jQuery(document).ready(function(){

        jQuery("button#cProgramEnabled").click(function(){
            jQuery(this).toggleClass("on").toggleClass("off");
            return false;
        });
        jQuery("button#cRestrictions").click(function(){
            jQuery(this).toggleClass("on").toggleClass("off");
            jQuery("#evenodd").toggle(jQuery(this).hasClass("off"));
            return false;
        });
        jQuery("button#cEvenOdd").click(function(){
            jQuery(this).toggleClass("on").toggleClass("off");
            return false;
        });
        jQuery("button#cWeeklyInterval").click(function(){
            jQuery(this).toggleClass("on").toggleClass("off");
            jQuery(".showInterval").toggle(jQuery(this).hasClass("off"));
            jQuery(".showWeekly").toggle(jQuery(this).hasClass("on"));
            if (jQuery(".distance0").length == 0) {
                jQuery("#intervalSelector .intervalSelect:first-child").trigger("click");
            }
            checkConsistency();
            return false;
        });
        jQuery("button#cRecurring").click(function(){
            jQuery(this).toggleClass("on").toggleClass("off");
            jQuery("#recurr").toggle();
            return false;
        });
        jQuery("table.stationList button.weekday.pushon, table.stationList button.station.toggle").click(function(){
            let id = jQuery(this).attr("id");
            let state = jQuery(this).hasClass("on");
            jQuery(this)
                .addClass(state ? "off": "on")
                .removeClass(state ? "on" : "off");
            if (id.indexOf("station") == 0) {
                jQuery("." + id).toggleClass("stationOn");
            } else if (id.indexOf("day") == 0) {
                jQuery("." + id).toggleClass("dayOn");
            }
            checkConsistency();
            return false;
        });
        jQuery(".stationState").click(function(){
            let classes = jQuery(this).attr("class");
            let stationName = classes.match(/station\d+/)[0];
            let dayName = classes.match(/day\d+/)[0];
            let stationOn = jQuery(this).hasClass("stationOn");
            let dayOn = jQuery(this).hasClass("dayOn");
            if (stationOn && dayOn) {
                jQuery("#" + stationName).trigger("click");
            } else if (stationOn && !dayOn) {
                jQuery("#" + dayName).trigger("click");
            } else if (!stationOn && dayOn) {
                jQuery("#" + stationName).trigger("click");
            } else {
                jQuery("#" + stationName).trigger("click");
                jQuery("#" + dayName).trigger("click");
            }
            return false;
        });
        jQuery("button#allWeekdays").click(function(){
            jQuery(".weekday").addClass("on").removeClass("off");
            jQuery(".day0, .day1, .day2, .day3, .day4, .day5, .day6").addClass("dayOn");
            checkConsistency();
            return false;
        });
        jQuery("button#noWeekdays").click(function(){
            jQuery(".weekday").addClass("off").removeClass("on");
            jQuery(".day0, .day1, .day2, .day3, .day4, .day5, .day6").removeClass("dayOn");
            checkConsistency();
            return false;
        });

        jQuery(".numbersOnly").keyup(function () {
            let newValue = this.value.replace(/[^0-9]/g, '');
            if (this.value != newValue) {
                this.value = newValue;
            }
        });
        jQuery("#intervalSelector").click(function() {
            let dayInterval = parseInt(jQuery("#intervalSelector .intervalSelect.distance0").text());
            let delayInterval = parseInt(jQuery("#intervalDelaySelector .intervalSelect.distance0").text());
            if (isNaN(delayInterval)) {
                delayInterval = 0;
            } else if (delayInterval > 1 && delayInterval >= dayInterval) {
                delayInterval = dayInterval - 1;
            }
            jQuery("#intervalDelaySelector").html("");
            for (let i=0; i<dayInterval; i++) {
                jQuery("#intervalDelaySelector").append(
                        jQuery("<span class='intervalSelect'>" + i + "</span>")
                            .on("click", intervalSelectClick)
                            .on("mouseover", intervalSelectMouseover)
                            .on("mouseout", intervalSelectMouseout)
                );
                if (i == 16) {
                    jQuery("#intervalDelaySelector").append("<br/>");
                }
            }
            jQuery("#intervalDelaySelector .intervalSelect").each(function() {
                if (jQuery(this).text() == delayInterval) {
                    jQuery(this).trigger("click");
                }
            });
        });
        jQuery("#intervalSelector .intervalSelect").each(function() {
            let thisValue = parseInt(jQuery(this).text());
            if (thisValue == prog['interval_base_day']) {
                jQuery(this).trigger("click");
                jQuery("#intervalSelector").trigger("click");
            }
        });

        jQuery("button#cSubmit").click(function(){
            let idd = ${gv.sd['idd']};
            let days = 0;
            let dayInterval = 0;
            let i, s, sid;
          prog['enabled'] = jQuery("button#cProgramEnabled").hasClass("on") ? 1 : 0;
          
            // process days
            if (jQuery("button#cWeeklyInterval").hasClass("on")) {
                prog['type'] = 'alldays';
                for (i=0; i<7; i++) {
                    if (jQuery("button#day"+i).hasClass("on")) {
                        days |= (1<<i);
                    }
                }

             if (jQuery("#cRestrictions").hasClass("off")) {
                 if (jQuery("#cEvenOdd").hasClass("off")) {
                   prog['type'] = 'odddays';
                 } else {
                   prog['type'] = 'evendays';
                 }
             }
             } else {
                prog['type'] = 'interval';
                dayInterval = parseInt(jQuery("#intervalSelector .intervalSelect.distance0").text());
                days = parseInt(jQuery("#intervalDelaySelector .intervalSelect.distance0").text());

                if (days < 0 || days >= dayInterval) {
                    alert($:{json.dumps(_(u'Starting in days wrong.'), ensure_ascii=False)});
                    return;
                }
             }
             
            // process stations
            let stations = [0];
            for (let bid = 0; bid < nbrd; bid ++) {
                stations[bid] = 0;
                for (let s=0; s < 8; s ++) {
                    sid = bid * 8 + s;
                    if (jQuery("button#station" + sid).hasClass("on")) {
                        stations[bid] |= 1<<s;
                    }
                }
            }

            // process general duration
            let dm = parseInt(jQuery("#tdm").val());
            let ds = parseInt(jQuery("#tds").val());
            let gduration = dm * 60 + ds;
            if(!idd) {                           	
                if (!(dm >= 0 && ds >= 0 && gduration > 0)) {
                    alert($:{json.dumps(_("Please enter a Duration to continue."), ensure_ascii=False)});
                    return;
                }
            }

            // Process individual station times
            let t = "[";
            let lap_t = 0;
            let sduration = 0;
            let idurations;
            if(idd) {
            for (let bid=0; bid<nbrd; bid++) {
                for (let s = 0; s < 8; s ++) {
                    sid = bid * 8 + s;
                    let stationOn = jQuery("button#station"+sid).hasClass("on")
                    if (stationOn) {
                        if (idd) {
                            let dm = parseInt(jQuery("#tdm" + sid).val());
                            let ds = parseInt(jQuery("#tds" + sid).val());
                            sduration = dm * 60 + ds;
                            if (!(dm >= 0 && ds >= 0 && ds < 60 && sduration > 0)) {
                                alert($:{json.dumps(_('Duration must be later than start.'), ensure_ascii=False)});
                                return;
                            }
                        } else {
                               sduration = gduration;
                        }
                    } else {
                        sduration = 0;
                    }
                    t += sduration;
                    if (seq) {
                        lap_t += sduration;
                    } else {
                        lap_t = Math.max(lap_t, sduration);
                    }
                    if(s < 7)
                        t += ",";
                }
                if (bid < (nbrd-1)) {
                    t += ",";
                }
            }
            t += "]";
            idurations = JSON.parse(t)
            }
           

            // process time
            let startTime = parseTime("ts");
            let interval = 0;
            let endTime;
            if (jQuery("button#cRecurring").hasClass("on")) {  //Single pass
                if (idd) {
                    endTime = Math.round(startTime + idurations.reduce((a,b) => a + b, 0) / 60);
                } else {
                    endTime = Math.round(startTime + (gduration));
                }   
            } else {                                           //recurring
                interval = parseTime("ti");
                endTime = parseTime("te");
            }
            if (startTime >= endTime) {
                // Possible bug - can you run a program from 10PM to 2AM?
                alert($:{json.dumps(_(u'End time must be later than start time.'), ensure_ascii=False)});
                return;
            }

            let v = {};                                     //// format conversion
            v['type'] = prog['type']; 
            v['enabled'] = prog['enabled'];
            v['day_mask'] = days;
            v['interval_base_day'] = dayInterval;
            v['start_min'] = startTime;
            v['stop_min'] = endTime;
            v['cycle_min'] = interval;
            v['duration_sec'] = [[gduration], idurations][idd]; // select one or the other
            v['name'] = jQuery("#pname").val();
            v['station_mask']  = stations;
//         let vs = JSON.stringify(v);                      //// format conversion
         jQuery("form#mf input[name='v']").val(JSON.stringify(v));
         jQuery("form#mf").submit();
        });  
         jQuery("button#cCancel").click(function(){
            window.location="/vp";
        });
    });
    
let durationTime = ${two_digits(int(program['duration_sec'][0]) % 60)};
let cycleTime = ${two_digits(program['cycle_min'] % 60)};

</script>
<div id="programs">
    <div class="title">${_(u"Edit Program #") + str(pid+1) if (pid>-1) else _(u"Add a New Program")}</div>
    <form name="mf" id="mf" action="cp" method="get">
        <input type="hidden" name="pid" value="${pid}">
        <input type="hidden" name="v" value="$:{program}">
        
        
        <div style="padding-left:5px;padding-right:5px;">
            <p><button id="cProgramEnabled" class="toggle ${'on' if program['enabled'] else 'off'}"><span class='toggleleft'>$_(u'Program On')</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u'Program Off')</span></button></p>

            <div class="controlblock">
                <p>
                    <label for="pname"><b>$_(u'Program name'):</b> </label><input type="text" id="pname" name="pname" value = "${p_name}">
                </p>
                <p>
                $ t = formatTime(two_digits(program['start_min'] / 60) + ":" + two_digits(program['start_min'] % 60))
                
                    <label class="timeInput"><b>$_(u'Start Time'):</b> <input class="timeInput numbersOnly" type="number" size = "2" maxlength = "2" id = "tsh" value = "${t.split(":")[0]}"> : </label>
                    <label class="timeInput"><input class="timeInput numbersOnly" type="number" size = "2" maxlength = "2" id = "tsm" value = "${t.split(":")[1][0:2]}">
                $if tf:
                    (hh:mm)
                $else:
                    <select id='tsf'>
                        <option ${"selected" if t.find(u"am") >= 0 else ""}>AM</option>
                        <option ${"selected" if t.find(u"pm") >= 0 else ""}>PM</option>
                    </select></label>
                </p>
                <p ${"" if not idd else "style=display:none"}><label class="timeInput"><b>$_(u'Duration'):</b> <input class="timeInput numbersOnly" type="number" size = "2" maxlength = "3" id = "tdm" value="${two_digits(int(program['duration_sec'][0]) / 60)}"> : </label>
                <label class="timeInput"><input class="timeInput numbersOnly" type="number" size="2" maxlength="2" id="tds" value="${two_digits(int(program['duration_sec'][0]) % 60)}"> (mm:ss)</label></p>
                <p><button id = "cRecurring" class = "toggle choice ${('off') if recurring else ('on')}"><span class='toggleleft'>$_(u'Single pass')</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u'Recurring')</span></button></p>
                <div id="recurr" $:{"" if recurring else "style='display:none'"}>
                    <p><label class="timeInput"><b>$_(u'Every'):</b> <input class="timeInput numbersOnly" type="number" size = "2" maxlength = "2" id = "tih" value = "${two_digits(program['cycle_min'] / 60)}"> : </label>
                    <label class="timeInput"><input class="timeInput numbersOnly" type = "number" size = "2" maxlength = "2" id = "tim" value="${two_digits(program['cycle_min'] % 60)}"> (hh:mm)</label></p>
                    <p>
                    $ t = formatTime(two_digits(program[u"stop_min"] // 60) + ":" + two_digits(program[u"stop_min"] % 60))
                        <label class="timeInput"><b>$_(u"Until"):</b> <input class="timeInput numbersOnly" type="number" size = "2" maxlength = "2" id = "teh" value = "${t.split(":")[0]}"> : </label>
                        <label class="timeInput"><input class="timeInput numbersOnly" type = "number" size = "2" maxlength = "2" id = "tem" value = "${t.split(":")[1][0:2]}">
                    $if tf:
                        (hh:mm)
                    $else:
                        <select id='tef'>
                            <option ${"selected" if t.find("am") >= 0 else ""}>AM</option>
                            <option ${"selected" if t.find("pm") >= 0 else ""}>PM</option>
                        </select>
                    </label></p>
                </div>
            </div>
            <p><button id="cWeeklyInterval" class="toggle choice ${'on' if weekly else 'off'}"><span class='toggleleft'>$_(u"Weekly")</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u"Interval")</span></button></p>
            <table id="stations" class="stationList">
                <tr class="showWeekly" $:{u"" if weekly else "style = 'display:none'"}>
                    <td colspan="3"></td>
                    <td colspan="7" style="text-align:center">
                        <button id="allWeekdays" class="execute">$_(u"Select All")</button>
                        <button id="noWeekdays" class="execute">$_(u"Clear All")</button>
                    </td>
                </tr>
                <tr class="showWeekly" $:{u"" if weekly else "style='display:none'"}>
                    <td colspan="2"></td>
                    <td><span ${"" if idd else "style=display:none"}><b>$_(u"Duration"):</b></span></td>
                    <td><button id="day0" class="weekday pushon ${"on" if program['day_mask']&(1<<0) else "off"}">$_(u"Monday")</button></td>
                    <td><button id="day1" class="weekday pushon ${"on" if program['day_mask']&(1<<1) else "off"}">$_(u"Tuesday")</button></td>
                    <td><button id="day2" class="weekday pushon ${"on" if program['day_mask']&(1<<2) else "off"}">$_(u"Wednesday")</button></td>
                    <td><button id="day3" class="weekday pushon ${"on" if program['day_mask']&(1<<3) else "off"}">$_(u"Thursday")</button></td>
                    <td><button id="day4" class="weekday pushon ${"on" if program['day_mask']&(1<<4) else "off"}">$_(u"Friday")</button></td>
                    <td><button id="day5" class="weekday pushon ${"on" if program['day_mask']&(1<<5) else "off"}">$_(u"Saturday")</button></td>
                    <td><button id="day6" class="weekday pushon ${"on" if program['day_mask']&(1<<6) else "off"}">$_(u"Sunday")</button></td>
                </td>
                $ firstTime = True
                $for bid in range(gv.sd['nbrd']):
                    $for s in range(8):
                        $ sid = bid*8 + s;
                        $ sn = sid + 1
                        $ show = (gv.sd[u"show"][bid]>>s)&1
                        $if show == 1 and sn != gv.sd[u"mas"]:
                            $ stationEnabled = program['station_mask'][bid]&(1<<s)
                                      
                            <tr>
                                <td class='station_name'>${snames[sid]}</td>
                                <td>
                                    <button id="station${sid}" class='station toggle narrow ${u"on" if stationEnabled else u"off"}'><span class='toggleleft'>$_(u"On")</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u"Off")</span></button>
                                </td>
                                <td>
                                <div class="oneline">
                                    <span ${u"" if idd else "style=display:none"}><label class="timeInput"><input class = "timeInput numbersOnly" type = "number" size = "2" maxlength="3" id="tdm${sid}" value="${two_digits(program['duration_sec'][sid if idd else 0] / 60)}"> : &nbsp;</label>
                                    <label class="timeInput"><input class="timeInput numbersOnly" type="number" size="2" maxlength="2" id="tds${sid}" value="${two_digits(program['duration_sec'][sid if idd else 0] % 60)}"> (mm:ss)</label></span>
                                </div>
                                </td>
                                $for d in range(7):
                                    $ status = ("stationOn" if stationEnabled else "") + (" dayOn" if program['day_mask']&(1<<d) else "")
                                    <td class="showWeekly stationState ${status} station${sid} day${d}" $:{"" if weekly else "style='display:none'"}></td>
                                $if firstTime:
                                    <td class="showInterval" $:{"style='display:none'" if weekly else ""} rowspan="${stationsShown}">
                                        <p>$_(u'Water interval'):</p>
                                        <div id="intervalSelector" class="animatedSelector controlblock oneline">
                                            <!--  Customize this with any set of intervals you like up to 127 -->
                                            <span class="intervalSelect ${"distance0" if weekly else ""}">2</span>
                                            <span class="intervalSelect">3</span>
                                            <span class="intervalSelect">4</span>
                                            <span class="intervalSelect">5</span>
                                            <span class="intervalSelect">6</span>
                                            <span class="intervalSelect">7</span>
                                            <span class="intervalSelect">10</span>
                                            <span class="intervalSelect">12</span>
                                            <span class="intervalSelect">14</span>
                                            <span class="intervalSelect">15</span>
                                            <span class="intervalSelect">21</span>
                                            <span class="intervalSelect">30</span>
                                        </div>
                                        <p>$_(u"Starting in"):</p>
                                        <div id="intervalDelaySelector" class="animatedSelector controlblock">
                                            $if weekly:
                                                <span class="intervalSelect distance0">0</span>
                                                <span class="intervalSelect distance1">1</span>
                                            $else:
                                                <span class="intervalSelect distance0">${pdays(program['day_mask'], program['interval_base_day'])}</span>
                                        </div>
                                    </td>
                                    $ firstTime = False
                            </tr>
                <tr class="showWeekly" $:{u"" if weekly else "style='display:none'"}>
                    <td colspan="2"></td>
                    <td colspan="7">
                        <button id="cRestrictions" class="toggle choice ${'off' if even or odd else 'on'}"><span class='toggleleft'>$_(u"Any Day")</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u"Restrict Day")</span></button>
                        <span id="evenodd" $:{u"" if even or odd else "style='display:none'"}>
                            <button id="cEvenOdd" class="toggle choice ${'on' if even else 'off'}" ><span class='toggleleft'>$_(u"Even")</span><span class='togglesep'>&nbsp;</span><span class='toggleright'>$_(u"Odd")</span></button>
                            $_(u'(except 31st and Feb 29th)')</span>
                    </td>
                </tr>
            </table>
        </div>
    </form>
</div>

<div class="controls">
    <button id="cSubmit" class="submit"><b>$_(u"Save")</b></button>
    <button id="cCancel" class="cancel danger">$_(u"Cancel")</button>
    <span id="errorHint"></span>
</div>